---
title: useStorage
description: The useStorage hook can be used to read and write from localStorage (default) or sessionStorage. The default behavior will automatically sync the value across tabs using the StorageEvent.
docType: API Docs
docGroup: Hooks
group: UI and State
hooks: [useStorage]
---

# useStorage [$SOURCE](packages/core/src/storage/useStorage.ts)

```ts disableTransform
function useStorage<T>(options: StorageOptions<T>): StorageImplementation<T>;
```

The `useStorage` hook can be used to control a **single value** and persist it
to [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).

## Example Usage

The `useStorage` hook can be used to read and write from `localStorage`
(default) or `sessionStorage`. The default behavior will automatically sync
the value across tabs using the `StorageEvent`.

```tsx
import { TextField } from "@react-md/core/form/TextField";
import { useStorage } from "@react-md/core/storage/useStorage";

function Example() {
  const { value, setValue } = useStorage({
    key: "savedSearch",
    defaultValue: "",
  });

  return (
    <TextField
      label="Search"
      placeholder="Search..."
      type="search"
      value={value}
      onChange={(event) => {
        setValue(event.currentTarget.value);
      }}
    />
  );
}
```

### Type-safe Objects

The `value` can be type-safe by providing the value as a type parameter and a
`deserializer` function that validates the value in local storage.

```tsx
import { useStorage } from "@react-md/core/storage/useStorage";
import { type ReactElement } from "react";

interface ExpectedSchema {
  label: string;
  value: string;
  // others
}

function Example(): ReactElement {
  const { value, setValue } = useStorage<ExpectedSchema | null>({
    key: "someKey",
    defaultValue: null,

    // this is optional: you can create a custom deserializer to validate
    // the stored value to prevent people manually updating local storage in
    // the dev tools
    deserializer(item) {
      const parsed = JSON.parse(item);
      const { label, value } = parsed;
      if (typeof label !== "string" || typeof value !== "string") {
        return null;
      }

      return { label, value };
    },
  });

  // do something
  // value will be `ExpectedSchema | null`
}
```

### Manual Persistence

The `useStorage` hook defaults to automatically saving the current `value`
in local storage immediately. To allow manual persisting to local storage,
enable the `manual` option and use the `persist()` or `remove()` functions.

```tsx
import { Button } from "@react-md/core/button/Button";
import { Checkbox } from "@react-md/core/form/Checkbox";
import { Form } from "@react-md/core/form/Form";
import { useStorage } from "@react-md/core/storage/useStorage";
import { type ReactElement } from "react";

function Example(): ReactElement {
  const { value, setValue, remove, persist } = useStorage({
    key: "someKey",
    manual: true,
    defaultValue: false,
  });

  return (
    <Form
      onSubmit={() => {
        // current value will be saved into local storage
        persist();
      }}
      onReset={() => {
        // "someKey" will be removed from local storage
        remove();
      }}
    >
      <Checkbox
        label="Allow cookies"
        checked={value}
        onChange={(event) => {
          setValue(event.currentTarget.checked);
        }}
      />
      <Button type="reset">Decline</Button>
      <Button type="submit">Save</Button>
    </Form>
  );
}
```

## Parameters

- `options` - An object with the following definition:

````ts disableTransform
export interface StorageOptions<T> {
  /**
   * The storage key name to use. This can be set to an empty string for
   * internal usage of conditionally saving items to storage.
   */
  key: string;

  /**
   * The default value to use if an item does not exist in storage.
   */
  defaultValue: UseStateInitializer<T>;

  /**
   * Set this to `true` to update:
   *
   * - the default {@link serializer} to be:
   * ```
   * typeof value === "string" ? value : `${value}`
   * ```
   * - the default {@link deserializer} to not call `JSON.parse` if the
   *   {@link defaultValue} is a string.
   *
   * @defaultValue `typeof defaultValue === 'string'`
   */
  raw?: boolean;

  /**
   * Set this to `true` to require a manual `persist()` or `remove()` call
   * to update the storage value.
   *
   * @defaultValue `false`
   */
  manual?: boolean;

  /** @defaultValue `globalThis.localStorage` */
  storage?: Storage;

  /**
   * An optional function to serialize the `value` before storing it in local
   * storage.
   *
   * @defaultValue `JSON.stringify`
   */
  serializer?: (value: T) => string;

  /**
   * An optional function to deserialize the `value` if the item existed in
   * local storage.
   *
   * @defaultValue `JSON.parse`
   */
  deserializer?: (item: string) => T;
}
````

## Returns

````ts disableTransform
export interface StorageImplementation<T> {
  value: T;

  /**
   * Updates the {@link value} in state. When the
   * {@link StorageOptions.manual} option is `false`, the value will
   * also be updated in local storage immediately.
   */
  setValue: UseStateSetter<T>;

  /**
   * Remove the item from local storage.
   */
  remove: () => void;

  /**
   * Manually persist the current {@link value} into local storage. This is only
   * useful if the {@link StorageOptions.manual} option is `true`.
   *
   * @example Manual Persisting
   * ```tsx
   * import type { ReactElement } from "react";
   *
   * function Example(): ReactElement {
   *   const { value, setValue, persist } = useStorage({
   *     key: "someKey",
   *     manual: true,
   *     defaultValue: "",
   *   });
   *
   *   return (
   *     <>
   *       <Button onClick={closeDialog}>
   *         Cancel
   *       </Button>
   *       <Button
   *         onClick={async () => {
   *           await saveToDatabase(value);
   *           persist();
   *           closeDialog();
   *         }}
   *       >
   *         Confirm
   *       </Button>
   *     </>
   *   );
   * }
   * ```
   */
  persist: () => void;
}
````

## Utils

### getItemFromStorage [$SOURCE](packages/core/src/storage/utils.ts#L62)

```ts disableTransform
function getItemFromStorage<T>(options: GetItemFromStorageOptions<T>): T;
```

This is a low-level helper function get a value from storage (defaults to
`localStorage`). You'll most likely want to use a pre-built implementation
like `useStorage` instead.

#### Example Usage

```ts
import { getItemFromStorage } from "@react-md/core/storage/utils";

const values = ["a", "b", "c", "d"] as const;

const item1 = getItemFromStorage({
  key: "testKey",
  fallback: values[0],
  deserializer(item) {
    if (!values.includes(item)) {
      return values[0];
    }

    return item;
  },
});

const item2 = getItemFromStorage({
  key: "anotherKey",
  fallback: -1,
});

const item3 = getItemFromStorage({
  key: "anotherKey",
  fallback: -1,
  storage: sessionStorage,
});
```

#### Parameters

- `options` - An object with the following definition:

```ts disableTransform
export type ModifyStorageOptions = Pick<
  StorageOptions<unknown>,
  "key" | "storage"
>;

export interface GetItemFromStorageOptions<T> extends ModifyStorageOptions {
  /**
   * A value to use when the {@link key} does not exist in storage or there is
   * an error deserializing the value.
   */
  fallback: T;

  /** @see {@link StorageOptions.deserializer} */
  deserializer?: StorageDeserializer<T>;
}
```

#### Returns

The type-safe value.

### setItemInStorage [$SOURCE](packages/core/src/storage/utils.ts#L123)

```ts disableTransform
function setItemInStorage<T>(options: SetItemInStorageOptions<T>): void;
```

You'll most likely want to use `useStorage` instead, but this is a low-level
util to "safely" set an item in `localStorage` or `sessionStorage`.

#### Example Usage

```ts disableTransform
import { getItemFromStorage } from "@react-md/core/storage/utils";
import { identity } from "@react-md/core/utils/identity";

const values = ["a", "b", "c", "d"] as const;

setItemInStorage({
  key: "testKey",
  value: values[0],
  // store string value as-is
  serializer: identity,
});

setItemInStorage({
  key: "anotherKey",
  value: 100,
});

setItemInStorage({
  key: "anotherKey",
  value: 100,
  storage: sessionStorage,
});
```

#### Parameters

- `options` - An object with the following definition:

```ts disableTransform
export type ModifyStorageOptions = Pick<
  StorageOptions<unknown>,
  "key" | "storage"
>;

export interface SetItemInStorageOptions<T> extends ModifyStorageOptions {
  value: T;

  /** @see {@link StorageOptions.serializer} */
  serializer?: StorageSerializer<T>;
}
```

#### Returns

Nothing.
